<!-- 

如果只需要一个值的双向绑定，那么在父组件使用时，可以直接使用v-model="xxx"或v-model.id="xxx"都可以；
如果需要2个值的双向绑定，那么必须使用 v-model.id="xxx"  v-model.name="xxx" 

-->

<template>
    <div class="DataSelect">
        <el-select v-model="vModelData" :placeholder="placeholder" :clearable="clearable" @change="onChange" @clear="onClear" v-bind="$attrs">
            <el-option v-for="item in list" :key="item[value]" :label="item[label]" :value="item[value]"></el-option>
        </el-select>
    </div>
</template>

<script lang="ts" setup>
const props = defineProps({
    //双向绑定的的id和name
    id: [Number, Array, String],
    name: [String, Array],
    obj: null,

    //枚举类型
    enums: {
        type: Object,
    },

    //数组
    enumsArr: {
        type: Array,
    },

    //下拉列表显示名称
    label: {
        type: String,
        default: "text",
    },

    //下拉列表选择的值
    value: {
        type: String,
        default: "value",
    },

    //提示信息
    placeholder: {
        type: String,
        default: "请选择",
    },

    //带清空
    clearable: {
        type: Boolean,
        default: true,
    },
});

//下拉列表中保存的数据
const list = ref((props.enums && props.enums.ToArray()) || props.enumsArr);

//下拉列表v-model绑定的值
const vModelData = ref();

//$attrs的值
const attrs = useAttrs();

//用来记录各种选择方式选择出来的值，从选择开始到emit之前，都用这个对象来处理
const selectData = reactive({
    id: null,
    name: null,
    obj: null,
});

//组件是否可以添加条目
let _allowCreate = attrs["allow-create"] == "" || attrs["allow-create"] == true;

//组件是否可以多选
let _multiple = attrs.multiple == "" || attrs.multiple == true;

//选择过的旧值，用来对比选择的值有没有改变
let _oldSelectData = null;

//监听属性id的，用于回显时默认选择，给vModelData赋值
watch(
    () => props.id,
    (newVal, oldVal) => {
        vModelData.value = newVal;

        if (_multiple) {
            let res = [];

            vModelData.value?.forEach((x) => {
                var findItem = list.value.find((item) => {
                    return item[props.value] === x;
                });

                if (!Gx.IsEmpty(findItem)) {
                    res.push(findItem);
                }
            });

            if (res.length > 0) {
                let ids = res.map((x) => {
                    return x[props.value];
                });
                let names = res.map((x) => {
                    return x[props.label];
                });

                selectData.id = ids;
                selectData.name = names;
                selectData.obj = res;
            } else {
                selectData.id = null;
                selectData.name = null;
                selectData.obj = null;
            }
        } else {
            var findItem = list.value.find((x) => {
                return x[props.value] === newVal;
            });

            if (!Gx.IsEmpty(findItem)) {
                //找到对应项，则说明是选择的内容
                selectData.id = findItem[props.value];
                selectData.name = findItem[props.label];
                selectData.obj = findItem;
            } else {
                //找不到对应项，则说明是输入的内容
                selectData.id = null;
                selectData.name = null;
                selectData.obj = null;
            }
        }

        if (!DataSame()) {
            SetEmitData();
        }
    }
);

//加载事件
onMounted(() => {
    if (_allowCreate) {
        throw new Error("EnumSelect组件不能使用 allow-create 属性！");
    }

    vModelData.value = props.id;
});

//下拉列表框改变事件
const onChange = () => {
    selectData.id = null;
    selectData.name = null;
    selectData.obj = null;

    if (_multiple) {
        //多选
        let res = [];

        vModelData.value.forEach((x) => {
            var findItem = list.value.find((item) => {
                return item[props.value] === x;
            });

            if (!Gx.IsEmpty(findItem)) {
                res.push(findItem);
            }
        });

        if (res.length > 0) {
            let ids = res.map((x) => {
                return x[props.value];
            });
            let names = res.map((x) => {
                return x[props.label];
            });

            selectData.id = ids;
            selectData.name = names;
            selectData.obj = res;
        }
    } else {
        //单选
        var findItem = list.value.find((x) => {
            return x[props.value] === vModelData.value;
        });

        if (!Gx.IsEmpty(findItem)) {
            selectData.id = findItem[props.value];
            selectData.name = findItem[props.label];
            selectData.obj = findItem;
        }
    }

    //向外抛出一个事件，可在父组件中用来处理change事件
    SetEmitData();
    emit("change");
};

//下拉列表清空
const onClear = () => {
    selectData.id = null;
    selectData.name = null;
    selectData.obj = null;
    vModelData.value = null;

    SetEmitData();
    emit("change");
};

//2个数量是否相同
const DataSame = () => {
    let obj1 = Gx.DeepCopy(_oldSelectData);
    let obj2 = Gx.DeepCopy(selectData);

    if (Gx.IsEmpty(obj1) || Gx.IsEmpty(obj2)) {
        return;
    }

    //在这里删除obj，是为了怕obj里的数据有不同而导致比较不相同
    delete obj1.obj;
    delete obj2.obj;

    return Gx.SerializeObject(obj1) == Gx.SerializeObject(obj2);
};

//更新v-model相关数据，并记录到旧值
const SetEmitData = () => {
    emit("update:id", selectData.id);
    emit("update:name", selectData.name);
    emit("update:obj", selectData.obj);

    _oldSelectData = Gx.DeepCopy(selectData);
};

//设置下拉列表的值
const SetList = (arr) => {
    list.value = Gx.DeepCopy(arr);
};

const emit = defineEmits(["update:id", "update:name", "update:obj", "change"]);

defineExpose({ SetList });
</script>
